using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;
using JGSY.CMS.LowCode.Platform.Application.DTOs;
using JGSY.CMS.LowCode.Platform.Application.Interfaces;
using JGSY.CMS.LowCode.Platform.Domain.Interfaces;
using JGSY.CMS.LowCode.Platform.Domain.Entities;

namespace JGSY.CMS.LowCode.Platform.Application.Services
{
    /// <summary>
    /// 用户管理应用服务实现
    /// 提供用户注册、登录、信息查询等核心用户管理业务功能，
    /// 包括身份验证、密码管理、用户状态管理等完整的用户生命周期管理
    /// </summary>
    /// <remarks>
    /// 该服务负责处理用户相关的业务逻辑，包括：
    /// - 用户注册和账户创建
    /// - 用户登录和身份验证  
    /// - 用户信息查询和管理
    /// - 密码加密和验证
    /// - 登录状态追踪
    /// </remarks>
    public class UserAppService : IUserAppService
    {
        /// <summary>
        /// 用户数据仓储接口
        /// 用于执行用户相关的数据库操作
        /// </summary>
        private readonly IUserRepository _userRepository;
        
        /// <summary>
        /// 日志记录器
        /// 用于记录用户操作日志和错误信息
        /// </summary>
        private readonly ILogger<UserAppService> _logger;
        
        /// <summary>
        /// HTTP上下文访问器
        /// 用于获取当前HTTP请求的上下文信息，如用户身份、IP地址等
        /// </summary>
        private readonly IHttpContextAccessor _httpContextAccessor;

        /// <summary>
        /// 初始化用户应用服务
        /// </summary>
        /// <param name="userRepository">用户数据仓储接口，用于数据访问操作</param>
        /// <param name="logger">日志记录器，用于记录操作日志</param>
        /// <param name="httpContextAccessor">HTTP上下文访问器，用于获取请求上下文</param>
        public UserAppService(
            IUserRepository userRepository,
            ILogger<UserAppService> logger,
            IHttpContextAccessor httpContextAccessor)
        {
            _userRepository = userRepository;
            _logger = logger;
            _httpContextAccessor = httpContextAccessor;
        }

        /// <summary>
        /// 获取当前登录用户的信息
        /// </summary>
        /// <returns>当前用户的数据传输对象，如果用户未登录则返回null</returns>
        /// <exception cref="Exception">获取用户信息时发生数据库访问错误</exception>
        /// <remarks>
        /// 该方法通过HTTP上下文中的用户身份声明获取用户ID，
        /// 然后从数据库查询对应的用户信息并转换为DTO格式返回
        /// </remarks>
        public async Task<UserDto?> GetCurrentUserAsync()
        {
            try
            {
                var userId = GetCurrentUserId();
                if (userId == null)
                {
                    return null;
                }

                var user = await _userRepository.GetByIdAsync(userId.Value);
                return user == null ? null : MapToDto(user);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error getting current user");
                throw;
            }
        }

        /// <summary>
        /// 用户登录验证
        /// </summary>
        /// <param name="username">用户名，用于标识登录用户</param>
        /// <param name="password">密码，用于验证用户身份</param>
        /// <returns>登录成功时返回JWT令牌字符串</returns>
        /// <exception cref="UnauthorizedAccessException">用户名或密码错误，或用户账户被禁用时抛出</exception>
        /// <exception cref="Exception">登录过程中发生数据库访问或其他系统错误</exception>
        /// <remarks>
        /// 登录流程包括：
        /// 1. 验证用户名和密码
        /// 2. 检查用户账户状态
        /// 3. 更新最后登录时间和IP地址
        /// 4. 生成并返回JWT令牌
        /// </remarks>
        public async Task<string> LoginAsync(string username, string password)
        {
            try
            {
                // 这里应该实现真正的身份验证逻辑
                // 包括密码验证、生成JWT令牌等
                var user = await _userRepository.GetByUsernameAsync(username);
                
                if (user == null || !VerifyPassword(password, user.PasswordHash))
                {
                    throw new UnauthorizedAccessException("用户名或密码错误");
                }

                if (user.Status != 1)
                {
                    throw new UnauthorizedAccessException("用户账户已被禁用");
                }

                // 更新最后登录信息
                user.LastLoginTime = DateTime.UtcNow;
                user.LastLoginIp = GetClientIpAddress();
                await _userRepository.UpdateAsync(user);

                _logger.LogInformation("User logged in successfully: {Username}", username);
                
                // 返回JWT令牌（这里简化处理，实际应该生成真正的JWT）
                return GenerateJwtToken(user);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error during login for user {Username}", username);
                throw;
            }
        }

        /// <summary>
        /// 用户注册
        /// </summary>
        /// <param name="username">用户名，必须唯一且符合规范</param>
        /// <param name="email">邮箱地址，必须唯一且格式正确</param>
        /// <param name="password">密码，将被加密存储</param>
        /// <param name="phone">手机号码，可选参数</param>
        /// <returns>注册操作的异步任务</returns>
        /// <exception cref="InvalidOperationException">用户名或邮箱已存在时抛出</exception>
        /// <exception cref="Exception">注册过程中发生数据库访问或其他系统错误</exception>
        /// <remarks>
        /// 注册流程包括：
        /// 1. 检查用户名和邮箱的唯一性
        /// 2. 加密用户密码
        /// 3. 创建用户实体并保存到数据库
        /// 4. 记录操作日志
        /// </remarks>
        public async Task RegisterAsync(string username, string email, string password, string? phone = null)
        {
            try
            {
                // 检查用户名是否已存在
                var existingUser = await _userRepository.GetByUsernameAsync(username);
                if (existingUser != null)
                {
                    throw new InvalidOperationException("用户名已存在");
                }

                // 检查邮箱是否已存在
                if (!string.IsNullOrEmpty(email))
                {
                    var existingEmailUser = await _userRepository.GetByEmailAsync(email);
                    if (existingEmailUser != null)
                    {
                        throw new InvalidOperationException("邮箱已被注册");
                    }
                }

                var user = new User
                {
                    Username = username,
                    Email = email,
                    Phone = phone,
                    PasswordHash = HashPassword(password),
                    Status = 1,
                    CreatedAt = DateTime.UtcNow,
                    UpdatedAt = DateTime.UtcNow
                };

                await _userRepository.AddAsync(user);
                _logger.LogInformation("User registered successfully: {Username}", username);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error registering user {Username}", username);
                throw;
            }
        }

        #region Private Methods

        /// <summary>
        /// 获取当前登录用户的ID
        /// </summary>
        /// <returns>当前用户ID，如果用户未登录则返回null</returns>
        /// <remarks>
        /// 通过HTTP上下文中的NameIdentifier声明获取用户ID
        /// </remarks>
        private long? GetCurrentUserId()
        {
            var userIdClaim = _httpContextAccessor.HttpContext?.User?.FindFirst(ClaimTypes.NameIdentifier);
            if (userIdClaim != null && long.TryParse(userIdClaim.Value, out var userId))
            {
                return userId;
            }
            return null;
        }

        /// <summary>
        /// 获取客户端IP地址
        /// </summary>
        /// <returns>客户端IP地址字符串，无法获取时返回"unknown"</returns>
        /// <remarks>
        /// 优先从X-Forwarded-For头获取真实IP，否则使用RemoteIpAddress
        /// </remarks>
        private string GetClientIpAddress()
        {
            var context = _httpContextAccessor.HttpContext;
            if (context == null) return "unknown";

            var ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(ip))
            {
                ip = context.Request.Headers["X-Real-IP"].FirstOrDefault();
            }
            if (string.IsNullOrEmpty(ip))
            {
                ip = context.Connection.RemoteIpAddress?.ToString();
            }
            return ip ?? "unknown";
        }

        /// <summary>
        /// 验证用户输入的密码是否与存储的哈希值匹配
        /// </summary>
        /// <param name="password">用户输入的明文密码</param>
        /// <param name="hash">数据库中存储的密码哈希值</param>
        /// <returns>密码匹配返回true，否则返回false</returns>
        /// <remarks>
        /// 使用BCrypt算法进行密码验证，确保密码安全性
        /// </remarks>
        private bool VerifyPassword(string password, string hash)
        {
            // 这里应该使用真正的密码验证逻辑（如BCrypt）
            // 简化实现
            return BCrypt.Net.BCrypt.Verify(password, hash);
        }

        /// <summary>
        /// 对用户密码进行哈希加密
        /// </summary>
        /// <param name="password">用户输入的明文密码</param>
        /// <returns>加密后的密码哈希值</returns>
        /// <remarks>
        /// 使用BCrypt算法进行密码加密，自动生成盐值以增强安全性
        /// </remarks>
        private string HashPassword(string password)
        {
            // 使用BCrypt哈希密码
            return BCrypt.Net.BCrypt.HashPassword(password);
        }

        /// <summary>
        /// 为用户生成JWT认证令牌
        /// </summary>
        /// <param name="user">用户实体对象</param>
        /// <returns>JWT令牌字符串</returns>
        /// <remarks>
        /// TODO: 此方法当前为简化实现，生产环境中需要实现真正的JWT令牌生成逻辑，
        /// 包括设置过期时间、签名密钥、用户声明等
        /// </remarks>
        private string GenerateJwtToken(User user)
        {
            // 这里应该实现真正的JWT令牌生成
            // 简化处理，返回用户ID
            return $"jwt_token_for_user_{user.Id}";
        }

        /// <summary>
        /// 将用户实体对象转换为数据传输对象
        /// </summary>
        /// <param name="user">用户实体对象</param>
        /// <returns>用户数据传输对象</returns>
        /// <remarks>
        /// 过滤敏感信息（如密码哈希），只传输必要的用户信息
        /// </remarks>
        private static UserDto MapToDto(User user)
        {
            return new UserDto
            {
                Id = user.Id,
                Username = user.Username,
                Email = user.Email ?? string.Empty,
                Phone = user.Phone,
                DisplayName = user.RealName,
                Avatar = user.Avatar,
                IsActive = user.Status == 1,
                CreatedAt = user.CreatedAt,
                UpdatedAt = user.UpdatedAt
            };
        }

        #endregion
    }
}
